#include "egpd.h"

int
string2addr(char *network, int64_t subnet, struct ipaddr *address)
{
   struct in_addr t1;
   memset(&t1, 0, sizeof(struct in_addr));

   int retval = inet_pton(AF_INET, network, &t1);
   if (retval == 1) {
      if (subnet > 32 || subnet < 0) 
         error("%s:%d invalid ipv4 subnet %s/%lld",
               __func__, __LINE__, network, subnet);
      else if (subnet == 0 || subnet == 32)
         address->prefixlen = 32;
      else
         address->prefixlen = subnet;

      address->family = AF_INET;
      memcpy(&address->address.addr4, &t1, sizeof(struct in_addr));
   }
   else {
      struct in6_addr t2;
      memset(&t2, 0, sizeof(struct in6_addr));
      retval = inet_pton(AF_INET6, network, &t2);
      if (retval == 1) {
         if (subnet > 128 || subnet < 0)
            error("%s:%d invalid ipv6 subnet %s/%lld",
                  __func__, __LINE__, network, subnet);
         else if (subnet == 0 || subnet == 128)
            address->prefixlen = 128;
         else
            address->prefixlen = subnet;

         address->family = AF_INET6;
         memcpy(&address->address.addr6, &t2, sizeof(struct in6_addr));
      }
   }

   return retval;
}

struct prefixlist *
get_firstpfl()
{
   struct prefixlist *retval = NULL;
   if (conf) {
      retval = LIST_FIRST(&conf->pfl);
      if (retval == NULL)
         error("%s:%s:%d get_first(), head empty",
               __FILE__, __func__, __LINE__);
   }

   return retval;
}
      
struct egpd_group *
get_firstgroup()
{
   struct egpd_group *retval = NULL;
   if (conf) {
      retval = LIST_FIRST(&conf->groups);
      if (retval == NULL)
         error("%s:%s:%d get_firstgroup(), head empty",
               __FILE__, __func__, __LINE__);
   }

   return retval;
}

struct policy *
get_firstpolicy()
{
   struct policy *retval = NULL;
   if (conf) {
      retval = LIST_FIRST(&conf->policy);
      if (retval == NULL)
         error("%s:%s:%d get_firstpolicy(), head empty",
               __FILE__, __func__, __LINE__);
   }

   return retval;
}

struct prefixlist *
get_pflbyname(char *name)
{
   struct prefixlist *retval = NULL;
   if (name && conf) {
      LIST_FOREACH(retval, &conf->pfl, entry) {
         if (strncmp(retval->name, name, sizeof(name)) == 0) 
            break;
      }
   }

   return retval;
}

void
insert_prefixlist_topolicy(struct prefixlist *pfl)
{
   struct policy *pol = get_firstpolicy();
   u_int16_t cnt = pol->termcount;
   int pcount = pol->terms[cnt].from.pcount;
   if (pcount < MAXPREFIXLIMIT) {
      memcpy(
            &pol->terms[cnt].from.pfl[pcount], pfl, sizeof(struct prefixlist));
      pol->terms[cnt].from.pcount++;
   }
   else 
      error("policy %s term %s exceeds maximum allowed prefixlist %d",
            pol->name, pol->terms[cnt].name, MAXPREFIXLIMIT);
}

void
insert_route_topolicy(struct ipaddr *address)
{
   struct policy *pol = get_firstpolicy();
   u_int16_t cnt = pol->termcount;
   int rcount = pol->terms[cnt].from.rcount;
   if (rcount < MAXROUTES) {
      memcpy(
            &pol->terms[cnt].from.route[rcount], address, sizeof(
               struct ipaddr));
      pol->terms[cnt].from.rcount++;
   }
   else
      error("policy %s term %s exceeds maximum allowed routes %d",
            pol->name, pol->terms[cnt].name, MAXROUTES);
}

void
insert_aspath_topolicy(u_int16_t aspath)
{
   struct policy *pol = get_firstpolicy();
   pol->terms[pol->termcount].from.aspath = aspath;
}

char *
addr2string(struct ipaddr *addr)
{
   static char buffer[48];
   memset(buffer, '\0', sizeof(buffer));
   switch (addr->family) {
      case AF_INET:
         if (inet_ntop(addr->family, &addr->address.addr4, buffer,
                  sizeof( buffer)) == NULL) 
            warning("%s:%s:%d inet_ntop()", __FILE__, __func__, __LINE__);
         break;

      case AF_INET6:
         if (inet_ntop(addr->family, &addr->address.addr6, buffer,
                  sizeof(buffer)) == NULL)
            warning("%s:%s:%d inet_ntop()", __FILE__, __func__, __LINE__);
         break;
   }

   return buffer;
}

void
insert_neighbor_togroup(struct ipaddr *addr, int options)
{
   struct egpd_group *group = get_firstgroup();
   if (group->peercnt < MAXPEERS) {
      struct egpd_peer peer;
      memset(&peer, 0, sizeof(struct egpd_peer));
      memset(&peer.ip, 0, sizeof(struct ipaddr));
      memcpy(&peer.ip, addr, sizeof(struct ipaddr));
      if (options == 0) {
         peer.asnumber = group->remoteas;
         peer.route = NULL;
         memcpy(&group->peers[group->peercnt++],
               &peer, sizeof(struct egpd_peer));
      }
      else {
         memcpy(
               &group->peers[group->peercnt],
               &peer, sizeof(struct egpd_peer));
      }
   }
   else 
      error("%s:%s:%d number of peers exceeds allowed limit: %d", MAXPEERS);
}

struct policy *
get_policy(const char *policy)
{
   struct policy *retval = NULL;
   if (policy && conf) {
      struct policy *ptr;
      LIST_FOREACH(ptr, &conf->policy, entry) {
         if (strcmp(ptr->name, policy) == 0) {
            retval = ptr;
            break;
         }
      }
   }

   return retval;
}

int
addto_prefixlist(struct ipaddr *ip)
{
   int retval = 0;
   struct prefixlist *pflist = get_firstpfl();
   if (pflist->count < MAXPREFIX)
      memcpy(&pflist->list[pflist->count++], ip, sizeof(struct ipaddr));
   else
      retval = 1;

   return retval;
}
